package classfile

import "fmt"

/*
    解析class文件
    ClassFile文件结构体如实反映了Java虚拟机规范
    定义的class文件格式
 */

/*
Java类文件结构
ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
*/

type ClassFile struct {
    magic        uint32
    minorVersion uint16        //次版本号，固定是0
    majorVersion uint16        //主版本号，Java8是52
    constantPool ConstantPool  //常量池
    accessFlags  uint16        //访问标记
    thisClass    uint16        //类名索引
    superClass   uint16        //超类索引
    interfaces   []uint16      //接口索引表
    fields       []*MemberInfo //字段表
    methods      []*MemberInfo //方法表
    attributes   []AttributeInfo
}

//解析class文件，得到ClassFile结构体
func Parse(classData []byte) (cf *ClassFile, err error) {
    defer func() {
        if r := recover(); r != nil {
            var ok bool
            err, ok = r.(error)
            if !ok {
                err = fmt.Errorf("%v", r)
            }
        }
    }()

    cr := &ClassReader{classData}
    cf = &ClassFile{}
    cf.read(cr)
    return
}

//读取class文件
func (self *ClassFile) read(reader *ClassReader) {
    self.readAndCheckMagic(reader)
    self.readAndCheckVersion(reader)
    self.constantPool = readConstantPool(reader)
    self.accessFlags = reader.readUint16()
    self.thisClass = reader.readUint16()
    self.superClass = reader.readUint16()
    self.interfaces = reader.readUint16s()
    self.fields = readMembers(reader, self.constantPool)
    self.methods = readMembers(reader, self.constantPool)
    self.attributes = readAttributes(reader, self.constantPool)
}

func (self *ClassFile) readAndCheckMagic(reader *ClassReader) {
    magic := reader.readUint32()
    if magic != 0xCAFEBABE {
        panic("java.lang.ClassFormatError: magic!")
    }
}

func (self *ClassFile) readAndCheckVersion(reader *ClassReader) {
    self.minorVersion = reader.readUint16()
    self.majorVersion = reader.readUint16()
    switch self.majorVersion {
    case 45:
        return
    case 46, 47, 48, 49, 50, 51, 52:
        if self.minorVersion == 0 {
            return
        }
    }

    panic("java.lang.UnsupportedClassVersionError!")
}

//====================各种get方法====================

func (self *ClassFile) MinorVersion() uint16 {
    return self.minorVersion
}
func (self *ClassFile) MajorVersion() uint16 {
    return self.majorVersion
}
func (self *ClassFile) ConstantPool() ConstantPool {
    return self.constantPool
}
func (self *ClassFile) AccessFlags() uint16 {
    return self.accessFlags
}
func (self *ClassFile) Fields() []*MemberInfo {
    return self.fields
}
func (self *ClassFile) Methods() []*MemberInfo {
    return self.methods
}

func (self *ClassFile) ClassName() string {
    return self.constantPool.getClassName(self.thisClass)
}

//从常量池中查找超类名
func (self *ClassFile) SuperClassName() string {
    if self.superClass > 0 {
        return self.constantPool.getClassName(self.superClass)
    }
    return ""
}

//从常量池中查找接口名
func (self *ClassFile) InterfaceNames() []string {
    interfaceNames := make([]string, len(self.interfaces))
    for i, cpIndex := range self.interfaces {
        interfaceNames[i] = self.constantPool.getClassName(cpIndex)
    }
    return interfaceNames
}
